#!/usr/bin/env python
# encoding: utf-8

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

import os, time, random
from collections import OrderedDict
import json
import binascii

import serial
import serial.tools.list_ports

from six import unichr
import qtawesome as qta

from common.libs.Log import logging
from common.libs.MathFunc import MathFunc
from common.libs.Helper import Helper

# from ui.moveDialog import Ui_Dialog
from ui.moveWidget import Ui_Form

CONFIG_PATH = os.getcwd()+'/conf/axis.json'
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
    CONFIG = json.loads(f.read(), object_pairs_hook=OrderedDict)

class MoveWidget(QWidget, Ui_Form):
    signal_serial_send = pyqtSignal(str, str, str)

    # 读取信息
    readInfo_flag = False
    readInfo_step = 0
    # 单轴移动
    move_one_flag = False
    # 设置位置标志
    pos_reset_flag = False
    # 串口标志
    serial_flag = False
    
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle('移动窗口')

        # 设置字体
        self.font = QFont()
        self.font.setFamily("Agency FB")
        self.font.setPointSize(CONFIG['font'])

        # 尺寸
        self.size = QSize(100, 100)

        # 界面
        self.uiLoad()

        # 读取信息提示框
        self.readInfoMessageBox = QMessageBox()  # Message Box that doesn't run
        self.readInfoMessageBox.setIcon(QMessageBox.Warning)
        self.readInfoMessageBox.setText("信息读取中\r\n请稍后...")
        self.readInfoMessageBox.setWindowFlags(Qt.FramelessWindowHint)
        self.readInfoMessageBox.setWindowTitle("提示")
        self.readInfoMessageBox.setFont(self.font)
        self.readInfoMessageBox.setStandardButtons(QMessageBox.Ok)
        self.readInfoMessageBox.button(QMessageBox.Ok).hide()

        # 读取信息
        self.timer_readinfo = QTimer()
        self.timer_readinfo.timeout.connect(self.readInfoTimer)
        self.pushButton_read_info.clicked.connect(self.readInfo)
        self.pushButton_read_info.setFont(self.font)
        # self.pushButton_read_info.setMinimumSize(self.size)

        # 移动
        self.timer_move = QTimer()
        self.timer_move.timeout.connect(self.moveTimer)


    def uiLoad(self):
        self.doubleBox_current_dict = {}
        self.doubleBox_target_dict = {}
        self.combox_target_dict = {}
        self.btn_move_dict = {}
        self.btn_stop_dict = {}
        self.btn_pos_dict = {}
        self.btn_pos_reset_dict = {}
        self.tab_index_dict = {}
        self.axis_name_dict = {}
        i = 0
        config_axis = CONFIG['axis']
        size = self.size
        font = self.font

        self.tabWidget = QTabWidget()
        self.tabWidget.setFont(font)
        self.tabWidget.setStyleSheet("QTabBar::tab{width:100}")
        self.tabWidget.setTabPosition(QTabWidget.West)

        for k in config_axis:
            # 获取信息
            item = config_axis[k]
            name = item['name'] if 'name' in item else ''
            pos = item['pos'] if 'pos' in item else ''
            enable = int(item['enable']) if 'enable' in item else 0

            # 创建控件
            doubleBox_target = QDoubleSpinBox()
            doubleBox_target.setRange(-1000000, 1000000)
            doubleBox_target.setMinimumSize(size)
            doubleBox_target.setFont(font)
            doubleBox_target.setDecimals(3)
            doubleBox_current = QDoubleSpinBox()
            doubleBox_current.setRange(-1000000, 1000000)
            doubleBox_current.setMinimumSize(size)
            doubleBox_current.setFont(font)
            doubleBox_current.setDecimals(3)
            doubleBox_current.setEnabled(False)
            combox_target = QComboBox()
            combox_target.addItems(pos.split(','))
            combox_target.currentIndexChanged.connect(self.comboxTargetChanged)
            combox_target.setMinimumSize(size)
            combox_target.setFont(font)
            btn_move = QPushButton("移动")
            btn_move.clicked.connect(self.move_one)
            btn_move.setMinimumSize(size)
            btn_move.setFont(font)

            btn_stop = QPushButton("停止")
            btn_stop.clicked.connect(self.stop_one)
            btn_stop.setMinimumSize(size)
            btn_stop.setFont(font)

            btn_pos = QPushButton("获取位置")
            btn_pos.clicked.connect(self.pos_one)
            btn_pos.setMinimumSize(size)
            btn_pos.setFont(font)

            btn_pos_reset = QPushButton("重置位置")
            btn_pos_reset.clicked.connect(self.pos_reset)
            btn_pos_reset.setMinimumSize(size)
            btn_pos_reset.setFont(font)
            # spin_icon = qta.icon('fa.spinner', color='red',
            #                      animation=qta.Pulse(btn_pos))
            # btn_pos.setIcon(spin_icon)

            label_arrow = QLabel()
            label_arrow.setStyleSheet('color: green;')
            label_arrow.setFont(qta.font('fa', 64))
            label_arrow.setText(unichr(0xf063))
            label_arrow.setAlignment(Qt.AlignCenter)

            label_current_pos = QLabel("当前位置")
            label_current_pos.setFont(font)
            label_target_pos = QLabel("目标位置")
            label_target_pos.setFont(font)
            label_select_pos = QLabel("选择位置")
            label_select_pos.setFont(font)


            # label_tip = QLabel()
            # label_tip.setStyleSheet('color: red;')

            # tab = QWidget()
            # self.tabWidget.addTab(tab, "")
            # self.tabWidget.setTabText(self.tabWidget.indexOf(tab),  name)

            gridLayout = QGridLayout()
            gridLayout.addWidget(btn_pos_reset, 0, 1, 1, 1)
            gridLayout.addWidget(btn_pos, 1, 3, 1, 1)
            gridLayout.addWidget(btn_move, 2, 3, 1, 1)
            gridLayout.addWidget(btn_stop, 3, 3, 1, 1)

            gridLayout.addWidget(label_current_pos, 1, 0, 1, 1)
            gridLayout.addWidget(label_target_pos, 2, 0, 1, 1)
            gridLayout.addWidget(label_select_pos, 3, 0, 1, 1)

            gridLayout.addWidget(doubleBox_current, 1, 1, 1, 1)
            # gridLayout.addWidget(label_arrow, 1, 1, 1, 1)
            gridLayout.addWidget(doubleBox_target, 2, 1, 1, 1)
            gridLayout.addWidget(combox_target, 3, 1, 1, 1)

            groupBox = QGroupBox(name)
            groupBox.setLayout(gridLayout)

            # 保存控件
            self.axis_name_dict[k] = name
            self.doubleBox_current_dict[k] = doubleBox_current
            self.doubleBox_target_dict[k] = doubleBox_target
            self.combox_target_dict[k] = combox_target
            self.btn_move_dict[k] = btn_move
            self.btn_stop_dict[k] = btn_stop
            self.btn_pos_dict[k] = btn_pos
            self.btn_pos_reset_dict[k] = btn_pos_reset
            # self.tab_index_dict[k] = self.tabWidget.indexOf(tab)

            self.gridLayout_all.addWidget(groupBox, int(i/3), i%3, 1, 1)

            i += 1

        # self.gridLayout_all.addWidget(self.tabWidget, 0, 0, 1, 1)

    def move_one(self):
        obj = self.sender()  # 获取发射信号的对象
        for k in self.btn_move_dict:
            if self.btn_move_dict[k] == obj:
                if self.move_one_flag: # 正在移动，提示
                    QMessageBox.information(
                        self, '提示', '%s 正在运动中, 请等待运动完成后操作!' % self.axis_name_dict[self.move_one_axis], QMessageBox.Yes)
                else:
                    self.timer_move.start(CONFIG["moveOneTimer"])
                    self.move_one_flag = True
                    self.move_one_step = "START"
                    self.move_one_timeout_cnt = 0
                    self.move_one_axis = k
                break

    def stop_one(self):
        """ 停止移动 
        检测当前轴是否处于移动状态，如果是当前轴，停止移动当前轴, 不是当前轴，提示
        """
        obj = self.sender()  # 获取发射信号的对象
        for k in self.btn_stop_dict:
            if self.btn_stop_dict[k] == obj:
                if self.move_one_flag:
                    if self.move_one_axis == k: # 正在移动，提示
                        self.sendCmd(k, 'p', '0')
                    else:
                        QMessageBox.information(
                            self, '提示', '%s 正在运动中, 无法停止%s!' % (self.axis_name_dict[self.move_one_axis], k), QMessageBox.Yes)
                break

    def pos_one(self):
        """ 获取位置 """
        if self.move_one_flag: # 正在移动，提示
            QMessageBox.information(
                self, '提示', '%s 正在运动中, 请等待运动完成后操作!' % self.axis_name_dict[self.move_one_axis], QMessageBox.Yes)
            return
        obj = self.sender()  # 获取发射信号的对象
        for k in self.btn_pos_dict:
            if self.btn_pos_dict[k] == obj:
                self.sendCmd(k, 'q', '2')
                self.doubleBox_current_dict[k].setValue(0)
                break

    def pos_reset(self):
        """ 重置位置 """
        if self.move_one_flag: # 正在移动，提示
            QMessageBox.information(
                self, '提示', '%s 正在运动中, 请等待运动完成后操作!' % self.axis_name_dict[self.move_one_axis], QMessageBox.Yes)
            return
        obj = self.sender()  # 获取发射信号的对象
        for k in self.btn_pos_reset_dict:
            if self.btn_pos_reset_dict[k] == obj:
                pos, okPressed = QInputDialog.getText(self, "请输入位置","位置(示例：10.321)", QLineEdit.Normal, "0.000")
                if okPressed and pos != '':
                    self.pos_reset_flag = True
                    self.sendCmd(k, 't', '%s'%pos)
                break
    
    def moveTimer(self):
        tip = ""
        # 单轴移动
        if self.move_one_flag:
            logging.info("*"*10 + "MoveOne" + "*"*10)
            self.move_one_timeout_cnt += 1
            # logging.error("<移动超时计数>: %s"%self.move_one_timeout_cnt)
            if self.move_one_timeout_cnt > 2:
                self.move_one_flag = False
                self.timer_move.stop()
                logging.error("移动超时!")
                QMessageBox.information(
                    self, '提示', '移动超时, 设备通信无反应', QMessageBox.Yes)
                return

            axis = self.move_one_axis
            if self.move_one_step == "START":
                err = str(self.doubleBox_target_dict[axis].value(
                ) - self.doubleBox_current_dict[axis].value())
                logging.info("[%s轴]:移动: %s" % (axis, err))
                self.sendCmd(axis, 'p', err)
            if self.move_one_step == "GET_STATUS":
                logging.info("[%s轴]:获取运动状态" % axis)
                self.sendCmd(axis, 'q', '1')
            if self.move_one_step == "GET_POSITION" or self.move_one_step == "DONE":
                logging.info("[%s轴]:获取位置" % axis)
                self.sendCmd(axis, 'q', '2')

    def readInfo(self):
        self.timer_readinfo.start(CONFIG["readInfoTimer"])
        self.readInfo_flag = True
        self.readInfo_step = 0

        self.readInfo_pos_flag = True
        self.readInfo_motor_flag = False
        # 读取超时计数
        self.readInfo_timeout_cnt = 0

        self.readInfoMessageBox.exec()

    def readInfoTimer(self):
        if self.readInfo_flag:
            self.readInfo_timeout_cnt += 1
            logging.info("*"*10 + "ReadInfo" + "*"*10)
            logging.warn("<读取超时计数>: %s"%self.readInfo_timeout_cnt )
            if self.readInfo_timeout_cnt > 2:
                # 关闭读取信息对话框
                self.readInfoMessageBox.accept()
                self.readInfo_flag = False
                self.timer_readinfo.stop()
                logging.error("读取信息超时!")
                QMessageBox.information(
                    self, '提示', '读取信息超时, 设备通信无反应', QMessageBox.Yes)
                return
            if self.readInfo_step < len(CONFIG['axis']) :
                if self.readInfo_pos_flag:
                    self.sendCmd(chr(0x61+self.readInfo_step), 'q', '2')
                    logging.info("读取位置信息")
                elif self.readInfo_motor_flag:
                    self.sendCmd(chr(0x61+self.readInfo_step), 'q', '1')
                    logging.info("读取电机状态")
            else:
                if self.readInfo_pos_flag:
                    logging.info("读取位置完成")
                    self.readInfo_step = 0
                    self.readInfo_pos_flag = False
                    self.readInfo_motor_flag = True
                elif self.readInfo_motor_flag:
                    logging.info("读取电机完成")
                    self.readInfo_flag = False
                    self.timer_readinfo.stop()
                    # 关闭读取信息对话框
                    self.readInfoMessageBox.accept()
                    QMessageBox.information(
                        self, '提示', '信息读取完成!', QMessageBox.Yes)
                    self.serial_flag = False
    
    def serial_deal(self, recv):
        cmd_bytes = binascii.unhexlify(recv)
        logging.info(cmd_bytes)
        cmd_start = recv[0:2]
        # 获取当前是哪个轴
        axis = chr(int(cmd_start, 16))
        # 清除超时标志
        self.readInfo_timeout_cnt = 0
        self.move_one_timeout_cnt = 0
        cmd_len = int(recv[2:4], 16)
        logging.info("[cmd_len]:%s" % cmd_len)
        if cmd_len == 4:
            if self.move_one_flag:
                self.move_one_step = "GET_STATUS"
                logging.info("[开始移动]")
            if self.pos_reset_flag: # 设置位置
                self.pos_reset_flag = False
                QMessageBox.information(
                    self, '提示', '%s \r\n重置位置完成' % self.axis_name_dict[axis], QMessageBox.Yes)
        if cmd_len == 6:  # 走步状态返回
            logging.info("[走步状态]")
            state = recv[4:6]
            if self.move_one_flag:
                if state == "63":  # c : 走步完成
                    self.move_one_step = "DONE"
                    logging.info("[%s轴]: 走步完成" % axis)
                if state == "6E":  # n : 走步中
                    self.move_one_step = "GET_POSITION"  # 处于移动中, 进入获取位置步骤
                    logging.info("[%s轴]: 走步中..." % axis)
        if cmd_len == 9:  # 向上位机报告此轴当前位置
            logging.info("[位置信息]")
            pos = recv[4:12]
            pos = MathFunc.hexStrToNeg(pos) / 1000
            self.doubleBox_current_dict[axis].setValue(pos)
            logging.info("[%s轴]:%s" % (axis, pos))
            if self.move_one_flag:  # 单轴移动
                if self.move_one_step == "GET_POSITION":
                    self.move_one_step = "GET_STATUS"
                if self.move_one_step == "DONE":
                    self.move_one_flag = False
                    self.serial_flag = False
                    logging.info("移动完成!!！")
                    QMessageBox.information(
                        self, '提示', '%s \r\n移动完成' % self.axis_name_dict[self.move_one_axis], QMessageBox.Yes)

        if self.readInfo_flag:
            self.readInfo_step += 1
        logging.info("*"*20 + "Deal Done" + "*"*20)
        pass

    def sendCmd(self, axis, _type, data):
        # 调查串口标志
        self.serial_flag = True
        self.signal_serial_send.emit(axis, _type, data)


    def axisTextChangedName(self, tp, txt):
        self.tabWidget.setTabText(self.tab_index_dict[tp],  txt)

    def axisTextChangedPos(self, tp, txt):
        self.combox_target_dict[tp].clear()
        self.combox_target_dict[tp].addItems(txt.split(','))

    def comboxTargetChanged(self):
        obj = self.sender()  # 获取发射信号的对象
        for k in self.combox_target_dict:
            if self.combox_target_dict[k] == obj:
                try:
                    self.doubleBox_target_dict[k].setValue(
                        float(self.combox_target_dict[k].currentText()))
                except:
                    pass
                break

    def axisChangedEnable(self, tp, enable):
        if enable == True:
            self.combox_target_dict[tp].setEnabled(True)
            self.doubleBox_current_dict[tp].setEnabled(True)
            self.doubleBox_target_dict[tp].setEnabled(True)
            self.btn_move_dict[tp].setEnabled(True)
        if enable == False:
            self.combox_target_dict[tp].setEnabled(False)
            self.doubleBox_current_dict[tp].setEnabled(False)
            self.doubleBox_target_dict[tp].setEnabled(False)
            self.btn_move_dict[tp].setEnabled(False)

